#![allow(warnings)]
use std::{rc::Rc, cell::RefCell, fmt, sync::{Arc, Mutex}};

use crate::{classfile::{self, ConstantType}, rtda::Object};

use super::{class::Class, ClassRef, FieldRef, MethodRef, InterfaceMethodRef, InvokeDynamic, MethodHandle, MethodType};

// 运行时常量池 主要存放两类信息：字面量（literal）和符号引用（symbolic reference）。
// 字面量包括整数、浮点数和字符串字面量；
// 符号引用包括类符号引用、字段符号引用、方法符号引用和接口方法符号引用
#[derive(Clone)]
pub enum Constant {
    Int(i32),
    Float(f32),
    Long(i64),
    Double(f64),
    String(String),
    ClassRef(Arc<Mutex<ClassRef>>),
    FieldRef(Arc<Mutex<FieldRef>>),
    MethodRef(Arc<Mutex<MethodRef>>),
    InterfaceMethodRef(Arc<Mutex<InterfaceMethodRef>>),
    InvokeDynamic(Arc<Mutex<InvokeDynamic>>),
    MethodHandle(Arc<MethodHandle>),
    MethodType(Arc<MethodType>),
}

impl Constant {
    pub fn new(constant_type: &ConstantType, rt_cp: Arc<ConstantPool>) -> Option<Constant> {
        match constant_type {
            ConstantType::ConstantInteger(t) => Some(Self::Int(t.get_val())),
            ConstantType::ConstantFloat(t) => Some(Self::Float(t.get_val())),
            ConstantType::ConstantLong(t) => Some(Self::Long(t.get_val())),
            ConstantType::ConstantDouble(t) => Some(Self::Double(t.get_val())),
            ConstantType::ConstantString(t) => Some(Self::String(t.get_string())),
            ConstantType::ConstantClass(t) => Some(Self::ClassRef(Arc::new(Mutex::new(ClassRef::new_class_ref(rt_cp, t))))),
            ConstantType::ConstantFieldref(t) => Some(Self::FieldRef(Arc::new(Mutex::new(FieldRef::new_field_ref(rt_cp, t))))),
            ConstantType::ConstantMethodref(t) => Some(Self::MethodRef(Arc::new(Mutex::new(MethodRef::new_method_ref(rt_cp, t))))),
            ConstantType::ConstantInterfaceMethodref(t) => Some(Self::InterfaceMethodRef(Arc::new(Mutex::new(InterfaceMethodRef::new_interface_method_ref(rt_cp, t))))),
            ConstantType::ConstantInvokeDynamic(t) => Some(Self::InvokeDynamic(Arc::new(Mutex::new(InvokeDynamic::new_invoke_dynamic(rt_cp, t))))),
            ConstantType::ConstantMethodHandle(t) => Some(Self::MethodHandle(Arc::new(MethodHandle::new(rt_cp, t)))),
            ConstantType::ConstantMethodType(t) => Some(Self::MethodType(Arc::new(MethodType::new(t)))),
            _ => None
        }
    }

    pub fn new_by_obj(obj: *mut Object, rt_cp: Arc<ConstantPool>) -> Option<Constant> {
        unsafe {
            let class = {&*obj}.get_class();
            if "java/lang/Class" != &class.get_name() {
                // panic!("not class: {}", class.get_name()); // TODO
                return Some(Self::ClassRef(Arc::new(Mutex::new(ClassRef::new_class(rt_cp, class)))));
            }
            let obj_class = {&*obj}.get_extra().unwrap().get_class();
            return Some(Self::ClassRef(Arc::new(Mutex::new(ClassRef::new_class(rt_cp, obj_class)))));
        }
        None
    }

    pub fn int(&self) -> i32 {
        match self {
            Self::Int(val) => *val,
            _ => panic!("Constant type is not Int")
        }
    }

    pub fn float(&self) -> f32 {
        match self {
            Self::Float(val) => *val,
            _ => panic!("Constant type is not Float")
        }
    }

    pub fn long(&self) -> i64 {
        match self {
            Self::Long(val) => *val,
            _ => panic!("Constant type is not Long")
        }
    }

    pub fn double(&self) -> f64 {
        match self {
            Self::Double(val) => *val,
            _ => panic!("Constant type is not Double")
        }
    }

    // TODO 231018 返回值暂用 String 若后续可替换为 &str 则替换
    pub fn string(&self) -> String {
        match self {
            Self::String(val) => val.clone(),
            _ => panic!("Constant type is not String")
        }
    }

    pub fn class_ref(&self) -> Arc<Mutex<ClassRef>> {
        match self {
            Self::ClassRef(val) => val.clone(),
            _ => panic!("Constant type is not ClassRef")
        }
    }

    pub fn field_ref(&self) -> Arc<Mutex<FieldRef>> {
        match self {
            Self::FieldRef(val) => val.clone(),
            _ => panic!("Constant type is not FieldRef")
        }
    }

    pub fn method_ref(&self) -> Arc<Mutex<MethodRef>> {
        match self {
            Self::MethodRef(val) => val.clone(),
            _ => panic!("Constant type is not MethodRef")
        }
    }

    pub fn interface_method_ref(&self) -> Arc<Mutex<InterfaceMethodRef>> {
        match self {
            Self::InterfaceMethodRef(val) => val.clone(),
            _ => panic!("Constant type is not InterfaceMethodRef")
        }
    }

    pub fn invoke_dynamic(&self) -> Arc<Mutex<InvokeDynamic>> {
        match self {
            Self::InvokeDynamic(val) => val.clone(),
            _ => panic!("Constant type is not InvokeDynamic")
        }
    }

    pub fn method_type(&self) -> Arc<MethodType> {
        match self {
            Self::MethodType(val) => val.clone(),
            _ => panic!("Constant type is not MethodType")
        }
    }

    pub fn method_handle(&self) -> Arc<MethodHandle> {
        match self {
            Self::MethodHandle(val) => val.clone(),
            _ => panic!("Constant type is not MethodHandle")
        }
    }
}

impl fmt::Display for Constant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            Self::Int(v) => format!("Int: {}", v),
            Self::Float(v) => format!("Float: {}", v),
            Self::Long(v) => format!("Long: {}", v),
            Self::Double(v) => format!("Double: {}", v),
            Self::String(v) => format!("String: {}", v),
            Self::ClassRef(_) => format!("ClassRef"),
            Self::FieldRef(_) => format!("FieldRef"),
            Self::MethodRef(_) => format!("MethodRef"),
            Self::InterfaceMethodRef(_) => format!("InterfaceMethodRef"),
            Self::InvokeDynamic(_) => format!("InvokeDynamic"),
            Self::MethodHandle(_) => format!("MethodHandle"),
            Self::MethodType(_) => format!("MethodType"),
            _ => "None".to_string()
        };
        write!(f, "{}", s)
    }
}

// #[derive(Default)]
pub struct ConstantPool {
    class: Arc<Class>,
    pub consts: Vec<Option<Constant>>
}

impl ConstantPool {
    // 由class常量池生成
    pub fn new_constant_pool(class: Arc<Class>, cf_cp: Rc<RefCell<classfile::ConstantPool>>) -> Arc<ConstantPool> {
        let cp = cf_cp.borrow();
        let cp_count = cp.len();
        let consts = Vec::with_capacity(cp_count);
        let constant_pool = Arc::new(ConstantPool{class, consts});
        // 231027 ConstantPool unsafe 生成时常量需要获取常量池引用，同时常量池仅在生成时修改，且再添加结束后才会返回此引用，故用unsafe实现添加是安全的。
        unsafe {
            let ptr = Arc::as_ptr(&constant_pool) as *mut ConstantPool;
            let rt_cp = { &mut *ptr };
            for i in 0..cp_count {
                let cp_info = cp.get(i);
                if let Some(info) = cp_info {
                    rt_cp.consts.push(Constant::new(info, constant_pool.clone()));
                } else {
                    rt_cp.consts.push(None); 
                }
            }
        }
        constant_pool
    }

    pub fn get_constant(&self, index: usize) -> Option<Constant> {
        self.consts[index].clone()
    }

    pub fn get_class(&self) -> Arc<Class> {
        self.class.clone()
    }
}

impl fmt::Display for ConstantPool {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let string:Vec<String> = self.consts.iter()
        .map(|slot| 
            match slot {
                Some(s) => format!("{}", s),
                None => format!("None")
            }
        )
        .collect();
        write!(f, "consts: [{}]", string.join(","))
    }
}